package com.zoe.onelink.circuitbreaker.autoconfigure;

import com.alibaba.cloud.circuitbreaker.sentinel.ReactiveSentinelCircuitBreakerAutoConfiguration;
import com.alibaba.cloud.circuitbreaker.sentinel.ReactiveSentinelCircuitBreakerFactory;
import com.alibaba.cloud.circuitbreaker.sentinel.SentinelCircuitBreakerAutoConfiguration;
import com.alibaba.cloud.circuitbreaker.sentinel.SentinelCircuitBreakerFactory;
import com.alibaba.csp.sentinel.SphU;
import com.zoe.onelink.circuitbreaker.checker.OnelinkSentinelCircuitBreakerChecker;
import com.zoe.onelink.circuitbreaker.property.OnelinkCircuitBreakerProperties;
import com.zoe.onelink.circuitbreaker.sentinel.OnelinkSentinelCircuitBreakerFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
import org.springframework.cloud.client.circuitbreaker.Customizer;
import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreakerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>标题: </p>
 * <p>描述: </p>
 * <p>版权: Copyright (c) 2023</p>
 * <p>公司: 智业软件股份有限公司</p>
 *
 * @version: 1.0
 * @author: ruansheng
 * @date: 2023-01-17
 */
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(OnelinkCircuitBreakerProperties.class)
public class OnelinkCircuitBreakerAutoConfiguration {

    @Bean
    public OnelinkSentinelCircuitBreakerChecker onelinkCircuitBreakerChecker() {
        return new OnelinkSentinelCircuitBreakerChecker();
    }

    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass({SentinelCircuitBreakerAutoConfiguration.class, SphU.class})
    @AutoConfigureBefore(SentinelCircuitBreakerAutoConfiguration.class)
    @ConditionalOnProperty(prefix = OnelinkCircuitBreakerProperties.PREFIX, name = "enabled", matchIfMissing = true)
    @Slf4j
    static class OnelinkSentinelCircuitBreakerAutoConfiguration {

        @Bean
        @ConditionalOnMissingBean
        @ConditionalOnProperty(prefix = OnelinkCircuitBreakerProperties.PREFIX, name = "enabled", matchIfMissing = true)
        public CircuitBreakerFactory onelinkSentinelCircuitBreakerFactory() {
            log.info("[OneLinkFrm] 开启熔断器功能");
            return new OnelinkSentinelCircuitBreakerFactory();
        }

    }

    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass({SentinelCircuitBreakerAutoConfiguration.class, SphU.class})
    @AutoConfigureBefore(SentinelCircuitBreakerAutoConfiguration.class)
    @ConditionalOnProperty(prefix = OnelinkCircuitBreakerProperties.PREFIX, name = "enabled", matchIfMissing = true)
    @Slf4j
    public static class SentinelCustomizerConfiguration {

        @Autowired(required = false)
        private List<Customizer<SentinelCircuitBreakerFactory>> customizers = new ArrayList<>();

        @Autowired(required = false)
        private SentinelCircuitBreakerFactory factory;

        @PostConstruct
        public void init() {
            if (this.customizers == null || this.factory == null) {
                log.warn("SentinelCircuitBreakerFactory is null or customizers is null");
                return;
            }
            customizers.forEach(customizer -> customizer.customize(factory));
        }

    }


    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass({Mono.class, Flux.class, ReactiveSentinelCircuitBreakerAutoConfiguration.class})
    @ConditionalOnProperty(prefix = OnelinkCircuitBreakerProperties.PREFIX, name = "enabled", matchIfMissing = true)
    static class OnelinkReactiveSentinelCircuitBreakerAutoConfiguration {

        @Autowired(required = false)
        private List<Customizer<ReactiveSentinelCircuitBreakerFactory>> customizers = new ArrayList<>();

        @Bean
        @ConditionalOnMissingBean(ReactiveCircuitBreakerFactory.class)
        public ReactiveCircuitBreakerFactory reactiveSentinelCircuitBreakerFactory() {
            ReactiveSentinelCircuitBreakerFactory factory = new ReactiveSentinelCircuitBreakerFactory();
            customizers.forEach(customizer -> customizer.customize(factory));
            return factory;
        }

    }


}
